/*
 * I am converting this grammar right back to C++!. - nfd 17/Nov/2006
*/

/*
 * PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
 *
 * Authors: Sumana Srinivasan, NeXT Inc.;            sumana_srinivasan@next.com
 *          Terence Parr, Parr Research Corporation; parrt@parr-research.com
 *          Russell Quong, Purdue University;        quong@ecn.purdue.edu
 *
 * VERSION 1.2
 *
 * SOFTWARE RIGHTS
 *
 * This file is a part of the ANTLR-based C++ grammar and is free
 * software.  We do not reserve any LEGAL rights to its use or
 * distribution, but you may NOT claim ownership or authorship of this
 * grammar or support code.  An individual or company may otherwise do
 * whatever they wish with the grammar distributed herewith including the
 * incorporation of the grammar or the output generated by ANTLR into
 * commerical software.  You may redistribute in source or binary form
 * without payment of royalties to us as long as this header remains
 * in all source distributions.
 *
 * We encourage users to develop parsers/tools using this grammar.
 * In return, we ask that credit is given to us for developing this
 * grammar.  By "credit", we mean that if you incorporate our grammar or
 * the generated code into one of your programs (commercial product,
 * research project, or otherwise) that you acknowledge this fact in the
 * documentation, research report, etc....  In addition, you should say nice
 * things about us at every opportunity.
 *
 * As long as these guidelines are kept, we expect to continue enhancing
 * this grammar.  Feel free to send us enhancements, fixes, bug reports,
 * suggestions, or general words of encouragement at parrt@parr-research.com.
 * 
 * NeXT Computer Inc.
 * 900 Chesapeake Dr.
 * Redwood City, CA 94555
 * 12/02/1994
 * 
 * Restructured for public consumption by Terence Parr late February, 1995.
 *
 * DISCLAIMER: we make no guarantees that this grammar works, makes sense,
 *             or can be used to do anything useful.
 */
/* 2001-2002
 * Version 1.0
 * This C++ grammar file has been converted from PCCTS to run under 
 *  ANTLR to generate lexer and parser in C++ code by
 *  Jianguo Zuo and David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 */
/* 2003
 * Version 2.0 was published by David Wigg in September 2003
 */
/* 2004
 * Version 3.0 July 2004
 * This is version 3.0 of the C++ grammar definition for ANTLR to 
 *  generate lexer and parser in C++ code updated by
 *  David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 * wiggjd@bcs.ac.uk
 * blackse@lsbu.ac.uk
 *
 * See MyReadMe.txt for further information
 *
 * This file is best viewed in courier font with tabs set to 4 spaces
 */

header 
    {
	// The statements in this block appear in both CPPLexer.hpp and CPPParser.hpp
	#include "antlr/CharScanner.hpp"
	#include "CPPDictionary.hpp"

	#include "LineObject.hpp"	// Query use. See LineObject.cpp
	#include "var_types.hpp"	// Do not use. Should be deleted in the next version
	#include "ASTNode.hpp"

	extern void process_line_directive(const char *, const char *);
    }

options
	{
	language = "Cpp";
	}

{
//	The statements in this block appear only in CPPParser.cpp and not in CPPLexer.cpp

// DO NOT USE THESE CONSTANTS - THEY WILL BE DELETED IN THE NEXT VERSION
int id_type = ID_VAR_NAME;	// variable type: ID_FUN_NAME, ID_VAR_NAME, ID_INPUT_PARAMETER,
							// ID_CLASS_DEF, ID_SYSTEM_FUNCTION, ID_CONST_DECL, 
							// ID_TYPEDEF_VAR

int statementTrace = 0;	// Used to control selected (level) tracing (see support.cpp)
						// 1 Shows which external and member statements selected
						// 2 Shows above plus all declarations/definitions
						// 3 reserved for future use
						// 4 and above available for user


void CPPParser::init()
{
	//antlrTrace(false);	// This is a dynamic trace facility for use with -traceParser etc.
						// It requires modification in LLkParser.cpp and LLkParser.hpp
						//  otherwise it should be commented out (see MyReadMe.txt)
						// true shows antlr trace (can be set and reset during parsing)
						// false stops showing antlr trace 
						// Provided the parser is always generated with -traceParser this
						//  facility allows trace output to be turned on or off by changing
						//  the setting here from false to true or vice versa and then
						//  recompiling and linking CPPParser only thus avoiding the need
						//  to use antlr.Tool to re-generate the lexer and parser again. 
					
	// Creates a dictionary to hold symbols with 4001 buckets, 200 scopes and 800,000 characters
	// These can be changed to suit the size of program(s) being parsed
	symbols = new CPPDictionary(4001, 200, 800000);

	// Set template parameter and external scopes
	templateParameterScope = symbols->getCurrentScopeIndex();	// Set template parameter scope to 0
	symbols->saveScope();	// Advance currentScope from 0 to 1
	externalScope = symbols->getCurrentScopeIndex();	// Set external scope to 1

	// Declare predefined scope "std" in external scope
	CPPSymbol *a = new CPPSymbol("std", CPPSymbol::otTypedef);
	symbols->define("std", a);

	// Global flags to allow for nested declarations
	_td = false;		// For typedef
	_fd = false;		// For friend
	_sc = scInvalid;	// For StorageClass
	_tq = tqInvalid;	// For TypeQualifier
	_ts = tsInvalid;	// For TypeSpecifier
	_ds = dsInvalid;	// For DeclSpecifier

	functionDefinition = 0;
	qualifierPrefix[0] = '\0';
	enclosingClass = "";
	assign_stmt_RHS_found = 0;
	in_parameter_list = false;
	K_and_R = false;	// used to distinguish old K & R parameter definitions
	in_return = false;
	is_address = false;
	is_pointer = false;

	temp_nodes = NULL;
	temp_nodes_next = temp_nodes_end = 0;
	}

void CPPParser::uninit()
{
	delete symbols;
	free_temp_nodes();
}

}	// End of CPPParser.cpp block


class CPPParser extends Parser;

options
	{
	k = 2;
	exportVocab = STDC;
	buildAST =false;
	codeGenMakeSwitchThreshold = 2;
	codeGenBitsetTestThreshold = 3;
	}

{
public:
	#define CPPParser_MaxQualifiedItemSize 500
	#define TEMP_NODES_ALLOC 512

	// can't bitwise-OR enum elements together, this must be an int; damn!
	typedef unsigned long TypeSpecifier;   // note: must be > 16bits
	#define tsInvalid   0x0
	#define tsVOID      0x1
	#define tsCHAR      0x2
	#define tsSHORT     0x4
	#define tsINT       0x8
	#define tsLONG      0x10
	#define tsFLOAT     0x20
	#define tsDOUBLE    0x40
	#define tsSIGNED    0x80
	#define tsUNSIGNED  0x100
	#define tsTYPEID    0x200
	#define tsSTRUCT    0x400
	#define tsENUM      0x800
	#define tsUNION     0x1000
	#define tsCLASS     0x2000
	#define tsWCHAR_T   0x4000
	#define tsBOOL      0x8000

	enum TypeQualifier 
		{ 
		tqInvalid=0, tqCONST=1, tqVOLATILE, tqCDECL 
		};

	enum StorageClass 
		{
		scInvalid=0, scAUTO=1, scREGISTER,
		scSTATIC, scEXTERN, scMUTABLE
		};

	enum DeclSpecifier 
		{
		dsInvalid=0,
		dsVIRTUAL, dsINLINE, dsEXPLICIT, dsFRIEND
		};

	// JEL 3/26/96 changed to allow ORing of values
	typedef int QualifiedItem;
	#define qiInvalid     0x0
	#define qiType        0x1	// includes enum, class, typedefs, namespace
	#define qiDtor        0x2
	#define qiCtor        0x4
	#define qiOperator    0x8
	#define qiPtrMember   0x10
	#define qiVar         0x20
	#define qiFun         0x40

protected:
	// Symbol table management stuff
	CPPDictionary *symbols;
	int templateParameterScope;
	int externalScope;

	bool _td;			// For typedef
	bool _fd;			// For friend
	StorageClass _sc;	// For storage class
	TypeQualifier _tq;	// For type qualifier
	TypeSpecifier _ts;	// For type specifier
	DeclSpecifier _ds;	// For declaration specifier
		
	int functionDefinition;	// 0 = Function definition not being parsed
							// 1 = Parsing function name
							// 2 = Parsing function parameter list
							// 3 = Parsing function block

	char qualifierPrefix[CPPParser_MaxQualifiedItemSize+1];
	char *enclosingClass;
	int assign_stmt_RHS_found;
	bool in_parameter_list;	// DW 13/02/04 used within CPP_parser
	bool K_and_R;	// used to distinguish old K & R parameter definitions
	bool in_return;
	bool is_address;
	bool is_pointer;

	/* Keep track of temporary AST nodes */
	ASTNode **temp_nodes;
	int temp_nodes_next, temp_nodes_end;

	// Limit lookahead for qualifiedItemIs()
	enum 
		{ 
		MaxTemplateTokenScan = 200 
		};

public:
	void init();
	void uninit();

protected:
	// Semantic interface; You could subclass and redefine these functions
	//  so you don't have to mess with the grammar itself.
	
	// Symbol stuff
	virtual int qualifiedItemIsOneOf(QualifiedItem qiFlags, int lookahead_offset=0);
	virtual QualifiedItem qualifiedItemIs(int lookahead_offset=0);
	virtual int skipTemplateQualifiers(int& kInOut);
	virtual int skipNestedParens(int& kInOut);
	virtual int scopedItem(int k=1);
	virtual int finalQualifier(const int k=1);
	virtual int isTypeName(const char *s);
	virtual int isClassName(const char *s);
	virtual void end_of_stmt();

	// Scoping stuff
	virtual void enterNewLocalScope();
	virtual void exitLocalScope();
	virtual void enterExternalScope();
	virtual void exitExternalScope();

	// Aggregate stuff
	virtual void classForwardDeclaration(TypeSpecifier, DeclSpecifier,const char *);
	virtual void beginClassDefinition(TypeSpecifier, const char *);
	virtual void endClassDefinition();
	virtual void beginEnumDefinition(const char *);
	virtual void endEnumDefinition();
	virtual void enumElement(const char *);

	// Declaration and definition stuff
	virtual void declarationSpecifier(bool, bool, const char *, const char *, ASTNode *ts, DeclSpecifier);
	virtual void beginDeclaration();
	virtual void endDeclaration();
	virtual void beginConstructorDeclaration(const char *);
	virtual void endConstructorDeclaration();
	virtual void beginDestructorDeclaration(const char *);
	virtual void endDestructorDeclaration();
	virtual void beginParameterDeclaration();
	virtual void beginFieldDeclaration();
	virtual void beginFunctionDefinition();
	virtual void endFunctionDefinition();
	virtual void functionParameterList();
	virtual void functionEndParameterList(const int def);
	virtual void beginConstructorDefinition();
	virtual void endConstructorDefinition();
	virtual void beginDestructorDefinition();
	virtual void endDestructorDefinition();

	// Declarator stuff
	virtual void declaratorID(const char *, QualifiedItem);	// This stores new symbol with its type.
	virtual void declaratorArray();
	virtual void declaratorParameterList(const int def);
	virtual void declaratorEndParameterList(const int def);

	// template stuff
	virtual void templateTypeParameter(const char *);
	virtual void beginTemplateDeclaration();
	virtual void endTemplateDeclaration();
	virtual void beginTemplateDefinition();
	virtual void endTemplateDefinition();
	virtual void beginTemplateParameterList();
	virtual void endTemplateParameterList();

	// exception stuff
	virtual void exceptionBeginHandler();
	virtual void exceptionEndHandler();
	virtual void panic(const char *);

	// myCode functions ready for overriding in MyCode subclass
	virtual void myCode_pre_processing(int, char *[]);
	virtual void myCode_post_processing();
	virtual void myCode_end_of_stmt();
	virtual void myCode_function_direct_declarator(const char *);

	virtual ASTNode *mk_node(const char *);
	virtual ASTNode *exprnode_acc(ASTNode *, ASTNode *, const char *);

	// Temporary (guessing) AST nodes
	void free_temp_nodes();
}


translation_unit returns [ASTNode *node]
   {ASTNode *ed;}
   :  {enterExternalScope();} {node = mk_node("translation_unit");}
      (ed = external_declaration {node->add_child(ed);})+
	  EOF
      {exitExternalScope();}
   ;

external_declaration returns [ASTNode *node]
	{
	ASTNode *d, *th, *es, *dh, *db, *cd, *fd, *dn, *idl, *cds, *cfdd, *ds;
	const char *s; K_and_R = false;
	}
	:  
	(
	// Template explicit specialisation (DW 14/04/03)
	// Ref: http://msdn2.microsoft.com/library/c401y1kb(en-us,vs.80).aspx (nfd)
		("template" LESSTHAN GREATERTHAN)=>
		"template" LESSTHAN GREATERTHAN d = declaration
		{node = mk_node("template_specialisation"); node->add_child(d);}
	|
	// Class definition (templates too)
	// This is separated out otherwise the next alternative
	// would look for "class A { ... } f() {...}" which is
	// an unacceptable level of backtracking.

	// JEL Note:  Rule body does not need typedef, because
	// that is internal to "declaration", and it is invalid
	// to say "typedef template..."
	 	// Class definition
		(("typedef")? class_head)=>
		d = declaration {node = d;}
	|	
		// Class template definition
		(template_head class_head)=>
		th = template_head d = declaration
		{node = mk_node("template"); node->add_child(th); node->add_child(d);}
   |  
		// Enum definition (don't want to backtrack over this in other alts)
		("enum" (ID)? LCURLY)=>
		{node = mk_node("enum");}
		es = enum_specifier {node->add_child(es);}
		(idl = init_declarator_list {node->add_child(idl);})?
		SEMICOLON! {end_of_stmt();}
   |  
		// Destructor DEFINITION (templated or non-templated)
		((template_head)? dtor_head[1] LCURLY)=>
		(th = template_head)? dh = dtor_head[1] db = dtor_body
		{node = mk_node("unfinished_destructor");}
	|  
		// Constructor DEFINITION (non-templated)
		// JEL 4/3/96 Added predicate that works, once the
		// restriction is added that ctor cannot be virtual
		// and ctor_declarator uses a more restrictive id
		(	(options {warnWhenFollowAmbig = false;}:
			 cds = ctor_decl_spec)?
			{qualifiedItemIsOneOf(qiCtor)}?
		)=>
		cd = ctor_definition
		{node = mk_node("unfinished_non-templated constructor");}
   |  
		// User-defined type cast
		(("inline")? scope_override  conversion_function_decl_or_def)=>
		("inline")? s = scope_override cfdd = conversion_function_decl_or_def 
		{node = mk_node("unfinished_typecast");}
   |   
		// Function declaration
		(declaration_specifiers function_declarator[0] SEMICOLON!)=> 
		d = declaration
		{node = d;}
	|
		// Function definition
		(declaration_specifiers	function_declarator[1] LCURLY)=> 
		fd = function_definition {node = fd;}
	|
		// K & R Function definition
		(declaration_specifiers	function_declarator[1] declaration)=>
		{ K_and_R = true;}
		fd = function_definition {node = fd;}
	|  
		// templated forward class decl, init/decl of static member in template
		(template_head declaration_specifiers (init_declarator_list)? SEMICOLON! {end_of_stmt();})=>
		{ beginTemplateDeclaration(); }
		th = template_head ds = declaration_specifiers (idl = init_declarator_list)? SEMICOLON! {end_of_stmt();}
		{endTemplateDeclaration();}
		{node = mk_node("unfinished_templated_forward_class_decl");}
	|  
		// Templated FUNCTIONS and CONSTRUCTORS matched here.
		{beginTemplateDefinition();}
		th = template_head
		{node = mk_node("templated_function");}
		(  
			// Templated CONSTRUCTOR definition
            // JEL 4/3/96 Added predicate that works once the
            // restriction is added that ctor cannot be virtual
			(	ctor_decl_spec {qualifiedItemIsOneOf(qiCtor)}?)=>
			cd = ctor_definition {node->add_child(cd);}
		|
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON!)=> 
			d = declaration
			{node->add_child(d);}
		|  
			// Templated function definition
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			fd = function_definition {node->add_child(fd);}
		)
		{endTemplateDefinition();}
	|  
		dn = decl_namespace
		{node = mk_node("unfinished_namespace_decl");}
	|	
		// everything else (except templates)
		d = declaration {node = d;}
	|	
		SEMICOLON! {end_of_stmt();}
	)
	;	// end of external_declaration

decl_namespace returns [ASTNode *node]
	{const char *qid; ASTNode *ed;}
	:	
		"namespace" 
		(
			{node = mk_node("namespace");}
			(ns:ID {node->set_leaf(ns->getText().data());}
			{ _td = true; declaratorID(ns->getText().data(), qiType);
			})?
			// The following statement can be invoked to trigger selective antlr trace
			// Also see below
			//{if (strcmp((ns->getText()).data(),"xyz")==0) antlrTrace(True);}	// Used for diagnostic trigger
			LCURLY 
			{enterNewLocalScope();}
			(ed = external_declaration {node->add_child(ed);} )*
			{exitLocalScope();}
			RCURLY
			// The following should be implemented to match the optional statement above
			//{antlrTrace(False);}
		|
			{node = mk_node("unfinished_namespace_assignment");}
			ns2:ID 
			{ _td = true; declaratorID(ns2->getText().data(), qiType); }
			ASSIGNEQUAL qid = qualified_id SEMICOLON! {end_of_stmt();} 
		)
	;

member_declaration returns [ASTNode *node]
	{
	ASTNode *as, *d, *es, *mdl, *cds, *cd, *dh, *db, *fd, *cfdd, *ds, *cs, *md, *idl, *th;
	const char *q;
	}
	:
	(
		// Class definition
		// This is separated out otherwise the next alternative
		// would look for "class A { ... } f() {...}" which is
		// an unacceptable level of backtracking.
		( ("typedef")? class_head) => 
		d = declaration
		{node = d;}
	|  
		// Enum definition (don't want to backtrack over this in other alts)
		("enum" (ID)? LCURLY)=>
		{node = mk_node("member_declaration");}
		es = enum_specifier {node->add_child(es);}
		(mdl = member_declarator_list {node->add_child(mdl);})? SEMICOLON!	{end_of_stmt();}
	|
		// Constructor declarator
		(	ctor_decl_spec
			{qualifiedItemIsOneOf(qiCtor)}?
			ctor_declarator[0] SEMICOLON!
		)=>
		{node = mk_node("member_declaration");}
		cds = ctor_decl_spec  {node->add_child(cds);}
		cd = ctor_declarator[0] {node->add_child(cd);}
		SEMICOLON! {end_of_stmt();} // Constructor declarator
	|  
		// JEL Predicate to distinguish ctor from function
		// This works now that ctor cannot have VIRTUAL
		// It unfortunately matches A::A where A is not enclosing
		// class -- this will have to be checked semantically
		(	ctor_decl_spec
			{qualifiedItemIsOneOf(qiCtor)}?
			ctor_declarator[1]
			(COLON        // DEFINITION :ctor_initializer
			|LCURLY       // DEFINITION (compound Statement) ?
			)
		)=>
		{node = mk_node("member_declaration");}
		cd = ctor_definition  {node->add_child(cd);}
   |  
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		(dtor_head[0] SEMICOLON!)=>
		{node = mk_node("member_declaration");}
		dh = dtor_head[0] {node->add_child(dh);}
		SEMICOLON! {end_of_stmt();}	// Declaration
	|
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		(dtor_head[1] LCURLY)=>
		{node = mk_node("member_declaration");}
		dh = dtor_head[1] {node->add_child(dh);}
		db = dtor_body	{node->add_child(db);}// Definition
	|
		// Function declaration
		(declaration_specifiers	function_declarator[0] SEMICOLON!)=>
		d = declaration
		{node = d;}
	|  
		// Function definition
		(declaration_specifiers function_declarator[1] LCURLY)=>
		{ beginFieldDeclaration(); }
		fd = function_definition
		{node = fd;}
	|  
		// User-defined type cast
		(("inline")? conversion_function_decl_or_def)=>
		("inline")? cfdd = conversion_function_decl_or_def
		{node = mk_node("unfinished_udtc-439");}
	|  
		// Hack to handle decls like "superclass::member",
		// to redefine access to private base class public members
		(qualified_id SEMICOLON!)=>
		q = qualified_id SEMICOLON! {end_of_stmt();}
		{node = mk_node("unfinished_declhack-446");}
	|  
		// Member with a type or just a type def
		// A::T a(), ::T a, ::B a, void a, E a (where E is the enclosing class)
		(declaration_specifiers)=>
		{ beginFieldDeclaration(); }
		{node = mk_node("member_declaration");}
		ds = declaration_specifiers {node->add_child(ds);}
		(md = member_declarator_list {node->add_child(md);})?
		SEMICOLON! {end_of_stmt();}
	|  
		// Member without a type (I guess it can only be a function declaration or definition)
		(function_declarator[0] SEMICOLON!)=>
		{ beginFieldDeclaration(); }
		fd = function_declarator[0] SEMICOLON! {end_of_stmt();}
		{node = fd;}
	|
		// Member without a type (I guess it can only be a function definition)
		fd = function_declarator[1] cs = compound_statement {endFunctionDefinition();}
		{node = mk_node("member_declaration"); node->add_child(fd); node->add_child(cs);}
	|  
		// templated forward class decl, init/decl of static member in template
		// DW 27/06/03 Copied here from external_declaration since templates can now be nested
		(template_head ds = declaration_specifiers (init_declarator_list)? SEMICOLON!)=>
		{ beginTemplateDeclaration(); node = mk_node("member_declaration");}
		 th = template_head {node->add_child(th);}
		 ds = declaration_specifiers {node->add_child(ds);}
		 (idl = init_declarator_list {node->add_child(idl);} )? SEMICOLON!
		 {end_of_stmt();}
		{endTemplateDeclaration();}
	|  
		// Templated FUNCTIONS and CONSTRUCTORS matched here.
		// DW 27/06/03 Copied here from external_declaration since templates can now be nested
		{beginTemplateDefinition();}
		th = template_head {node = mk_node("templated_function"); node->add_child(th);}
		(
			// Templated CONSTRUCTOR definition
			// JEL 4/3/96 Added predicate that works once the
			// restriction is added that ctor cannot be virtual
			(ctor_decl_spec
			 {qualifiedItemIsOneOf(qiCtor)}?
			)=>
			cd = ctor_definition {node->add_child(cd);}
		|
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON!)=>
			d = declaration {node->add_child(d);}
		|  
			// Templated function definition
			// Function definition DW 2/6/97
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			fd = function_definition {node->add_child(fd);}
		|
			cfdd = conversion_function_decl_or_def {node->add_child(cfdd);}
		)
		{endTemplateDefinition();}
	|  
		as = access_specifier COLON
		{node = as;}
	|  
		SEMICOLON! {end_of_stmt();}
		{node = mk_node("unfinished_member-decl-524");}
	)
	;	// end member_declaration

function_definition returns [ASTNode *node]
	{
	ASTNode *ds, *fd, *decl_node, *d, *cs;
	}
	:	// don't want next action as an init-action due to (...)=> caller
	{beginFunctionDefinition(); node = mk_node("function_definition");}
	(	// Next line is equivalent to guarded predicate in PCCTS
		// (SCOPE | ID)? => <<qualifiedItemIsOneOf(qiType|qiCtor)>>?
		{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
		ds = declaration_specifiers {node->add_child(ds);}
		fd = function_declarator[1] {node->add_child(fd);}
		(	options{warnWhenFollowAmbig = false;}:
			{decl_node = mk_node("declaration_list");}
			(d = declaration {decl_node->add_child(d);})*	// Possible for K & R definition
			{in_parameter_list = false;}
			{node->add_child(decl_node);}
		)?
		cs = compound_statement {node->add_child(cs);}
	|	// Next line is equivalent to guarded predicate in PCCTS
		// (SCOPE | ID)? => <<qualifiedItemIsOneOf(qiPtrMember)>>?
		//{( !(LA(1)==SCOPE||self.LA(1)==ID) || (self.qualifiedItemIsOneOf(qiPtrMember)) )}?
		fd = function_declarator[1] {node->add_child(fd);}
		(	options{warnWhenFollowAmbig = false;}:
			{decl_node = mk_node("declaration_list");}
			(d = declaration)*	 {decl_node->add_child(d);}// Possible for K & R definition
			{in_parameter_list = false;}
			{node->add_child(decl_node);}
		)?
		cs = compound_statement {node->add_child(cs);}
	)
	{endFunctionDefinition();}
	;

declaration returns [ASTNode *node]
	{
	ASTNode *a, *idl, *ud, *ds, *ls;
	}
	:	
		("extern" StringLiteral)=>
		ls = linkage_specification {node = ls;}
	|	
		{beginDeclaration(); node = mk_node("declaration");}
		// LL 31/1/97: added (COMMA) ? below. This allows variables to typedef'ed more than once. DW 18/08/03 ?
		ds = declaration_specifiers {node->add_child(ds);}
		((COMMA)?
			(a = attribute {node->add_child(a);})?
			idl = init_declarator_list {node->add_child(idl);} )?
		SEMICOLON! {end_of_stmt();}
		{endDeclaration();}
	|	
		ud = using_declaration	// DW 19/04/04
		{node = ud;}
	;

linkage_specification returns[ASTNode *node]
	{
	ASTNode *ed, *d;
	node = mk_node("linkage_specification");
	}
	:	"extern"
		StringLiteral
		(LCURLY (ed = external_declaration {node->add_child(ed);})* RCURLY
		|d = declaration {node->add_child(d);}
		)
	;

declaration_specifiers returns [ASTNode *node]
	{
	char *specname;
	ASTNode *dd;
	
	// Global flags to allow for nested declarations
	_td = false;		// For typedef
	_fd = false;		// For friend
	_tq = tqInvalid;	// For TypeQualifier
	_ts = tsInvalid;	// For TypeSpecifier
	_ds = dsInvalid;	// For DeclSpecifier

	 // Locals
	bool td = false;	// For typedef
	bool fd = false;	// For friend
	char *sc = NULL;	// auto,register,static,extern,mutable
	char *tq = NULL;	// const,const_cast,volatile,cdecl
	ASTNode *ts = NULL;	// char,int,double, etc., class,struct,union
	// inline,virtual,explicit:
	DeclSpecifier ds = dsInvalid; 	
	}
	:
	(	
		{node = mk_node("declaration_specifiers");}
		(options {warnWhenFollowAmbig = false;}
		:
		(sc = storage_class_specifier {specname = sc;}
		|	tq = type_qualifier {specname = tq;}
		|   "__extension__" {specname = "__extension__";} /* nfd: gcc extension */
		|	("inline"^|"_inline"^|"__inline"^|"__inline__")
				{ds = dsINLINE; specname = "inline";}
		|	"virtual"^						{ds = dsVIRTUAL; specname = "virtual";}
		|	"explicit"^						{ds = dsEXPLICIT; specname = "explicit";}
		|	"typedef"^	{td=true;} {specname = "typedef";}
		|	"friend"^	{fd=true;} {specname = "friend";}
		|	("_stdcall"^|"__stdcall"^) {specname = "stdcall";}
		)
		{node->add_child(mk_node(specname));}

		)*
		ts = type_specifier[ds] {node->add_child(ts);}
	|	
		"typename"	{td=true;}
		{node = mk_node("declaration_specifiers");}
		dd = direct_declarator  {node->add_child(dd); node->set_leaf("typename");}
	)
	{declarationSpecifier(td,fd,sc,tq,ts,ds);}
	;

attribute returns[ASTNode *a]  /* nfd */
	{
	ASTNode *adl;
	a = mk_node("attribute");
	}
	: "__attribute__" LPAREN LPAREN adl = attribute_decl_list {a->add_child(adl);} RPAREN RPAREN
	;

attribute_decl_list returns[ASTNode *node]
	{
	node = mk_node("attribute_decl_list");

	ASTNode *c1, *c2;
	}
	: "__mode__" LPAREN ID RPAREN {node->set_name("mode");}
	| "packed" {node->set_name("packed");}
	| "const" {node->set_name("const");}
	| "__const" {node->set_name("const");} /* nfd: gcc extension */
	| "__noreturn__" {node->set_name("noreturn");}
	| "__returns_twice__" {node->set_name("returns_twice");}
	| "__noinline__" {node->set_name("noinline");}
	| "__always_inline__" {node->set_name("always_inline");}
	| "__flatten__" {node->set_name("flatten");}
	| "__pure__" {node->set_name("pure");}
	| "__const__" {node->set_name("const");}
	| "__nothrow__" {node->set_name("nothrow");}
	| "__sentinel__" {node->set_name("sentinel");}
	| "__format__" {node->set_name("format");} LPAREN ID COMMA c1=constant {node->add_child(c1);}
			COMMA c2=constant {node->add_child(c2);} RPAREN
	| "__format_arg__" {node->set_name("format_arg");}
	| "__no_instrument_function__" {node->set_name("no_instrument_function");}
	| "__section__" {node->set_name("section");}
	| "__constructor__" {node->set_name("constructor");}
	| "__destructor__" {node->set_name("destructor");}
	| "__used__" {node->set_name("used");}
	| "__unused__" {node->set_name("unused");}
	| "__deprecated__" {node->set_name("deprecated");}
	| "__weak__" {node->set_name("weak");}
	| "__malloc__" {node->set_name("malloc");}
	| "__alias__" {node->set_name("alias");}
	| "__warn_unused_result__" {node->set_name("warn_unused_result");}
	| "__nonnull__" {node->set_name("nonnull");} LPAREN c1=constant {node->add_child(c1);}
			(COMMA c2=constant {node->add_child(c2);})* RPAREN
	| "__externally_visible__" {node->set_name("externally_visible");}
	;

storage_class_specifier returns [char *s]
	:	"auto"		{s = "auto";}
	|	"register"	{s = "register";}
	|	"static"	{s = "static";}
	|	"extern"	{s = "extern";}
	|	"mutable"	{s = "mutable";}
	;

type_qualifier returns [char *s] // aka cv_qualifier
	:  ("const"|"const_cast"|"__const")	{s = "const";} 
	|  ("volatile"|"__volatile")				{s = "volatile";;}
	|  ("__restrict" | "__restrict__") {s = "__restrict";}
	;

type_specifier[DeclSpecifier ds] returns [ASTNode *node]
	:	node = simple_type_specifier
	|	node = class_specifier[ds]
	|	node = enum_specifier
	;

simple_type_specifier returns [ASTNode *node]
	{
	char *s;
	node = mk_node("simple_type_specifier");
	}
	:	(	{qualifiedItemIsOneOf(qiType|qiCtor)}? 
			 s = qualified_type {node->add_child(mk_node(s));}
		|	
			(	"char"		{node->add_child(mk_node("char"));}
			//|	"wchar_t"	{ts |= tsWCHAR_T;}  
			|	"bool"		{node->add_child(mk_node("bool"));}
			|	"short"		{node->add_child(mk_node("short"));}
			|	"int"		{node->add_child(mk_node("int"));}
			|	("_int64"|"__int64")	{node->add_child(mk_node("__int64"));}
			|	"__w64"		{node->add_child(mk_node("__w64"));}
			|	"long"		{node->add_child(mk_node("long"));}
			/* nfd: GCC type aliases for "signed" */
			|	("signed"^|"__signed"^|"__signed__"^)	{node->add_child(mk_node("signed"));}
			|	"unsigned"	{node->add_child(mk_node("unsigned"));}
			|	"float"		{node->add_child(mk_node("float"));}
			|	"double"	{node->add_child(mk_node("double"));}
			|	"void"		{node->add_child(mk_node("void"));}
			|	("_declspec"|"__declspec") LPAREN ID RPAREN 
			|   "__builtin_va_list" {node->add_child(mk_node("__builtin_va_list"));}
			)+
		|
		// Fix towards allowing us to parse *.cpp files directly
		(qualified_type qualified_id)=> s = qualified_type {node->add_child(mk_node(s));}
		)
	;

qualified_type returns [char *q]
	{
	ASTNode *tal;
	char *s; static char qitem[CPPParser_MaxQualifiedItemSize+1];
	}
	: 
		// JEL 3/29/96 removed this predicate and moved it upwards to
		// simple_type_specifier.  This was done to allow parsing of ~ID to 
		// be a unary_expression, which was never reached with this 
		// predicate on
		// {qualifiedItemIsOneOf(qiType|qiCtor)}?

		s = scope_override 
		id:ID 
		(options {warnWhenFollowAmbig = false;}:
		 LESSTHAN tal = template_argument_list GREATERTHAN
		)?
		{strcpy(qitem, s);}
		{strcat(qitem, (id->getText()).data());}
		{q = qitem;}
	;

class_specifier[DeclSpecifier ds] returns [ASTNode *node]
	{
	ASTNode *bases, *members, *md, *a;
	char *saveClass;
	const char *id;
	TypeSpecifier ts;
	}
	:	("class"^	{ts = tsSTRUCT; node = mk_node("class");}	
		|"struct"^	{ts = tsUNION; node = mk_node("struct");}
		|"union"^	{ts = tsCLASS; node = mk_node("union");}
		)
		(	id = qualified_id {node->set_leaf(id);}
			(options{generateAmbigWarnings = false;}:
				{saveClass = enclosingClass; enclosingClass = symbols->strdup(id); }
				(bases = base_clause {node->add_child(bases);})?
				LCURLY	 
				{beginClassDefinition(ts, id);}	// This stores class name in dictionary
				{members = mk_node("members");}
				(md = member_declaration {members->add_child(md);})*
				{endClassDefinition();}
				RCURLY
				{node->add_child(members); enclosingClass = saveClass;}
			|
				{classForwardDeclaration(ts, ds, id);}
			)
		|
			LCURLY	 
			{saveClass = enclosingClass; enclosingClass = "__anonymous";}
			{beginClassDefinition(ts, "anonymous");}
			{members = mk_node("members");}
			(md = member_declaration {members->add_child(md);})*
			{endClassDefinition();}
			{node->add_child(members);}
			RCURLY
			{enclosingClass = saveClass;}
		) 
		(a = attribute {node->add_child(a);})?
	;

enum_specifier returns [ASTNode *node]
	{
	ASTNode *el;
	node = mk_node("enum_specifier");
	}
	:	"enum"
		(	LCURLY el = enumerator_list {node->add_child(el);}RCURLY
		|	id:ID     {node->set_leaf(id->getText().data());}
				// DW 22/04/03 Suggest qualified_id here to satisfy elaborated_type_specifier
			{beginEnumDefinition((id->getText()).data());}
			(LCURLY el = enumerator_list {node->add_child(el);} RCURLY)?
			{endEnumDefinition();}
		)
	;

/* nfd: Optional trailing comma is a GCC-ism (mar 14 2006)*/
enumerator_list returns[ASTNode *node]
	{
	ASTNode *e;
	node = mk_node("enumerator_list");
	}
	:	e = enumerator {node->add_child(e);}
		/* nfd : it's always okay to choose this option when available,
		 * rather than the trailing comma and an error.
		*/
		( options {warnWhenFollowAmbig=false;} : COMMA e = enumerator {node->add_child(e);})*
		(COMMA)?
	;

enumerator returns[ASTNode *node]
	{
	node = mk_node("enumerator");
	ASTNode *cx;
	}
	:	id:ID {node->set_leaf(id->getText().data());}
		(ASSIGNEQUAL cx = constant_expression {node->add_child(cx);})?
		{enumElement(id->getText().data());}
	;

/* This matches a generic qualified identifier ::T::B::foo
 * (including OPERATOR).
 * It might be a good idea to put T::~dtor in here
 * as well, but id_expression in expr.g puts it in manually.
 * Maybe not, 'cause many people use this assuming only A::B.
 * How about a 'qualified_complex_id'?
 */
qualified_id returns [const char *q]
	{
	ASTNode *tal;
	const char *so, *o;
	static char qitem[CPPParser_MaxQualifiedItemSize+1];
	}
	:
	so =  scope_override
	{strcpy(qitem, so);}
	(  
	id:ID	(options{warnWhenFollowAmbig = false;}:
			 LESSTHAN tal = template_argument_list GREATERTHAN)?
	{strcat(qitem,(id->getText()).data());}
	|  
	OPERATOR o = optor
	{strcat(qitem,"operator"); strcat(qitem, o);}
	|
	"this"  // DW 21/07/03 fix to pass test8.i
	|
	("true"|"false")	// DW 21/07/03 fix to pass test8.i
	)
	{q = qitem;}
	;

typeID
	:	{isTypeName((LT(1)->getText()).data())}?
		ID
	;

init_declarator_list returns [ASTNode *node]
	{
	ASTNode *id, *a;
	node = mk_node("init_declarator_list");
	}
	:	id = init_declarator {node->add_child(id);}
		(COMMA id = init_declarator {node->add_child(id);})*
		(a = attribute {node->add_child(a);})*
	;

init_declarator returns [ASTNode *node]
	{
	ASTNode *d, *i, *el, *an;
	node = mk_node("init_declarator");
	}
	:	d = declarator {node->add_child(d);}
		(an = func_asm_name {node->add_child(an);})?
		(	
			ASSIGNEQUAL 
			i = initializer
			{node->add_child(i);}
		|	
			LPAREN el = expression_list RPAREN
			{node->add_child(el);}
		)?
	;

initializer returns [ASTNode *node]
   {
   ASTNode *rx, *i1, *i2, *d1, *i3, *d2, *i4;
   node = mk_node("initializer");
   }
   :  rx = remainder_expression {node->add_child(rx);}// DW 18/4/01 assignment_expression
   |  LCURLY i1 = initializer {node->add_child(i1);}
   		(COMMA i2 = initializer {node->add_child(i2);})* RCURLY
   |  d1 = gcc_designator {node->add_child(d1);}
   	i3 = initializer {node->add_child(i3);} /* nfd jul 2005 */
   |  d2 = c99_designator {node->add_child(d2);}
   		i4 = initializer {node->add_child(i4);}/* nfd jul 2005 */
   ;
 
/* Designated initializers, GCC extension, http://tigcc.ticalc.org/doc/gnuexts.html#SEC82 
 * These are of the form var = {structfield : val}
 * See below for c99 designators.
*/
gcc_designator returns [ASTNode *node]
	{node = mk_node("designator");}
	: id:ID COLON {node->set_leaf(id->getText().data());}
	;

/* C99 designated initializers, http://david.tribble.com/text/cdiffs.htm#C90-vs-CPP98
 * Of the form var = { .structfield = val}
*/
c99_designator returns [ASTNode *node]
	{node = mk_node("designator");}
	: DOT id:ID EQUALS {node->set_leaf(id->getText().data());}
	;

class_head returns [ASTNode *node]
	{
	ASTNode *tal, *bc;
	node = mk_node("class_head") ;
	}
	:	// Used only by predicates	
	("struct" {node->add_child(mk_node("struct"));}
	|"union" {node->add_child(mk_node("union"));}
	|"class" {node->add_child(mk_node("class"));}
	)
    (id:ID	{node->set_leaf(id->getText().data());}
		(LESSTHAN tal= template_argument_list {node->add_child(tal);} GREATERTHAN)?
		(bc = base_clause {node->add_child(bc);})? 
	)? LCURLY
	;

base_clause returns [ASTNode *node]
	{
	ASTNode *bs;
	node = mk_node("base_clause");
	}
	:	COLON bs = base_specifier {node->add_child(bs);}
		(COMMA bs = base_specifier {node->add_child(bs);})*
	;

base_specifier returns [ASTNode *node]
	{
	ASTNode *as;
	char *qt;
	}
	:	// DW 13/08/03 Should check qualified_type for class-name?
	{node = mk_node("base_specifier");}
	(	"virtual" {node->add_child(mk_node("virtual"));}
		(as = access_specifier {node->add_child(as);})?
		qt = qualified_type {node->add_child(mk_node(qt));}
	|	as = access_specifier {node->add_child(as);}
		("virtual" {node->add_child(mk_node("virtual"));})?
		qt = qualified_type {node->add_child(mk_node(qt));}
	|	qt = qualified_type {node->add_child(mk_node(qt));}
	)
	;

access_specifier returns[ASTNode *node]
	:	"public" {node = mk_node("public");}
	|	"protected" {node = mk_node("protected");}
	|	"private" {node = mk_node("private");}
	;

member_declarator_list returns [ASTNode *node]
	{
	ASTNode *md;
	node = mk_node("init_declarator_list");
	}
	:	md = member_declarator {node->add_child(md);}
		(COMMA md = member_declarator {node->add_child(md);} )*
	;

member_declarator returns [ASTNode *node]
	{ASTNode *c, *d, *a;}
	:	
		{node = mk_node("init_declarator_bitfield");}
		((ID)? COLON constant_expression)=>(id:ID {node->set_leaf(id->getText().data());})?
		COLON c = constant_expression {node->add_child(c);}
		(ASSIGNEQUAL OCTALINT {node->add_child(mk_node("purevirtual"));})?
	|  
		d = declarator {node = mk_node("init_declarator"); node->add_child(d);}
		(a = attribute {node->add_child(a);})?
		(ASSIGNEQUAL OCTALINT {node->add_child(mk_node("purevirtual"));})?
	;

conversion_function_decl_or_def returns [ASTNode *node]
		{
		char *tq;
		ASTNode *ds, *tpl, *pl, *es, *cs;
		node = mk_node("unfinished_conversion_function_decl_or_def");
		}
	:	OPERATOR ds = declaration_specifiers (STAR | AMPERSAND)?	// DW 01/08/03 Use type_specifier here? see syntax
		(LESSTHAN tpl = template_parameter_list GREATERTHAN)?
		LPAREN (pl = parameter_list)? RPAREN	
		(tq = type_qualifier)?
		(es = exception_specification)?
		(	cs = compound_statement
		|	SEMICOLON! {end_of_stmt();}
		)
	;

// JEL note:  does not use (const|volatile)* to avoid lookahead problems
cv_qualifier_seq returns[char *s]
	{
	char *tq;
	static char seq[CPPParser_MaxQualifiedItemSize+1];
	seq[0] = '\0';
	}
	:
	(tq = type_qualifier {strcat(seq, tq);})*
	{s = seq;}
	;

declarator returns [ASTNode *node]
	{
	ASTNode *d;
	char *p;
	}
	:
		{node = mk_node("declarator");}
		//{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiPtrMember) );}?
		(ptr_operator)=> p = ptr_operator {node->set_leaf(p);}	// AMPERSAND or STAR
		d = declarator {node->add_child(d);}
	|	
		{node = mk_node("declarator");}
		d = direct_declarator {node->add_child(d);}
	;

direct_declarator returns [ASTNode *node]
	{
	const char *id, *tq;
	ASTNode *d, *ds, *pl, *es, *el, *ce;
	}
	:
		{node = mk_node("direct_declarator");}
		(qualified_id LPAREN (RPAREN|declaration_specifiers) )=>	// Must be function declaration
		id = qualified_id {node->set_leaf(id);}
		{declaratorID(id, qiFun);}
		LPAREN {declaratorParameterList(0);}
		(pl = parameter_list {node->add_child(pl);} )?
		RPAREN {declaratorEndParameterList(0);}
		(tq = type_qualifier {node->add_child(mk_node(tq));} )*
		(es = exception_specification {node->add_child(es);} )?
	|	(qualified_id LPAREN qualified_id)=>	// Must be class instantiation
		{node = mk_node("direct_declarator");}
		id = qualified_id {node->set_leaf(id);}
		{declaratorID(id,qiVar);}
		LPAREN
		el = expression_list {node->add_child(el);}
		RPAREN
	|
		(qualified_id LSQUARE)=>	// Must be array declaration
		{node = mk_node("direct_declarator");}
		id = qualified_id {node->set_leaf(id);}
		{if (_td == true) declaratorID(id, qiType);}
		{if (_td != true) declaratorID(id, qiVar);}
		{is_address = false; is_pointer = false;}
		(options {warnWhenFollowAmbig = false;}:
                 LSQUARE (ce = constant_expression {node->add_child(ce);})?
                 RSQUARE)+
		{declaratorArray();}
		
	|
		{node = mk_node("direct_declarator");}
		id = qualified_id {node->set_leaf(id);}
		{if (_td == true) declaratorID(id,qiType);}
		{if (_td != true) declaratorID(id,qiVar);}
		{is_address = false; is_pointer = false;}
	|	
		{node = mk_node("direct_declarator");}
		// DW 24/05/04 This block probably never entered as dtor selected out earlier
		//	Note In fact no dictionary entries for ctor or dtor	
		TILDE dtor:ID {declaratorID(dtor->getText().data(),qiDtor);}	// Note "class" not recorded in CPPSymbol
		{printf("%d warning direct_declarator5 entered unexpectedly with %s\n",
				LT(1)->getLine(),(dtor->getText()).data());}
		LPAREN {declaratorParameterList(0);}
		(pl = parameter_list)?
		RPAREN {declaratorEndParameterList(0);}
		{node->add_child(mk_node("unfinished_direct_declarator"));}
	|	
		LPAREN d = declarator {node = d;} RPAREN ds = declarator_suffixes {node->add_child(ds);}
	;

declarator_suffixes returns [ASTNode *node]
	{
	ASTNode *cx, *pl, *es;
	char *tq;
	node = mk_node("declarator_suffixes");
	}
	:
	(
		(options {warnWhenFollowAmbig = false;}:
		 LSQUARE (cx = constant_expression {node->add_child(cx);})? RSQUARE)+
		{declaratorArray();}
	|	{(!((LA(1)==LPAREN)&&(LA(2)==ID))||(qualifiedItemIsOneOf(qiType|qiCtor,1)))}?
		LPAREN {declaratorParameterList(0);}
		(pl = parameter_list {node->add_child(pl);})?
		RPAREN {declaratorEndParameterList(0);}
		(tq = type_qualifier {node->add_child(mk_node(tq));})*
		(es = exception_specification {node->add_child(es);})?
//	|	// DW 28/06/04 deleted Assume either following bracketed declaration
//		// empty
	)
	;

/* I think something is weird with the context-guards for predicates;
 * as a result I manually hoist the appropriate pred from ptr_to_member
 *
 * TER: warning: seems that "ID::" will always bypass and go to 2nd alt :(
 */
function_declarator [int definition] returns [ASTNode *node]
	{
	char *po;
	ASTNode *fd, *fdd;
	node = mk_node("function_declarator");
	}
	:	
		//{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiPtrMember) )}?
		(ptr_operator)=> po = ptr_operator {node->set_leaf(po);}
		fd = function_declarator[definition] {node->add_child(fd);}
	|	
		fdd = function_direct_declarator[definition] {node->add_child(fdd);}
	;

function_direct_declarator [int definition] returns [ASTNode *node]
	{
	ASTNode *a, *pl, *es, *an;
	const char *q, *tq;
	node = mk_node("function_direct_declarator");
	}
	:
		/* predicate indicate that plain ID is ok here; this counteracts any
		 * other predicate that gets hoisted (along with this one) that
		 * indicates that an ID is a type or whatever.  E.g.,
		 * another rule testing isTypeName() alone, implies that the
		 * the ID *MUST* be a type name.  Combining isTypeName() and
		 * this predicate in an OR situation like this one:
		 * ( declaration_specifiers ... | function_declarator ... )
		 * would imply that ID can be a type name OR a plain ID.
		 */
		(	// fix prompted by (isdigit)() in xlocnum
			LPAREN
			q = qualified_id {node->set_leaf(q);}
			{declaratorID(q,qiFun);}
			RPAREN
		|
			(a = attribute {node->add_child(a);} )*
			q = qualified_id {node->set_leaf(q);}
			{declaratorID(q,qiFun);}
		)
		LPAREN 
		{functionParameterList();}
		{if (K_and_R == false) in_parameter_list = true;}
		(pl = parameter_list {node->add_child(pl);} )? 
		{if (K_and_R == false) in_parameter_list = false;}
		{if (K_and_R != false) in_parameter_list = true;}
		RPAREN
		(an = func_asm_name {node->add_child(an);})?
		(options{warnWhenFollowAmbig = false;}:
		 tq = type_qualifier {node->add_child(mk_node(tq));})*
		(ASSIGNEQUAL OCTALINT {node->add_child(mk_node("purevirtual"));})?	// The value of the octal must be 0
		{functionEndParameterList(definition);}
		(es = exception_specification {node->add_child(es);})?
	;

/* nfd: GCC extension, allows one to set the asm name of a function (the name
 * against which the function is linked).
 * Refer http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Asm-Labels.html
*/
func_asm_name returns [ASTNode *node]
	:
	{node = mk_node("func_asm_name");}
	("asm" | "__asm" | "__asm__")
	LPAREN
	(sl:StringLiteral {node->extend_leaf(sl->getText().data());})+
	RPAREN
	;

ctor_definition returns [ASTNode *node]
	{ASTNode *ch, *cb;
	node = mk_node("ctor_definition");
	}
	:
	ch = ctor_head {node->add_child(ch);}
	cb = ctor_body {node->add_child(cb);}
	{endConstructorDefinition();}
	;

ctor_head returns [ASTNode *node]
	{
	ASTNode *cds, *cd;
	node = mk_node("ctor_head");
	}
	:
	cds = ctor_decl_spec {node->add_child(cds);}
	cd = ctor_declarator[1] {node->add_child(cd);}
	;

ctor_decl_spec returns [ASTNode *node]
	{
	node = mk_node("ctor_decl_spec");
	}
	:
	(("inline"|"_inline"|"__inline") {node->add_child(mk_node("inline"));}
	|"explicit" {node->add_child(mk_node("explicit"));})*
	;

ctor_declarator[int definition] returns [ASTNode *node]
	{
	char *q;
	ASTNode *pl, *es;
	node = mk_node("ctor_declarator");
	}
	: 
	// JEL 4/3/96 qualified_id too broad DW 10/06/03 ?
	q = qualified_ctor_id {node->set_leaf(q);}
	{declaratorParameterList(definition);}
	LPAREN (pl = parameter_list {node->add_child(pl);} )? RPAREN
	{declaratorEndParameterList(definition);}
	(es = exception_specification {node->add_child(es);})?
	;

// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_ctor_id returns [char *q]
	{
	char *so;
	static char qitem[CPPParser_MaxQualifiedItemSize+1];
	}
	: 
	so = scope_override
	{strcpy(qitem, so);}
	id:ID	// DW 24/05/04 Note. Neither Ctor or Dtor recorded in dictionary
	{strcat(qitem,(id->getText()).data());}
	{q = qitem;}
	;

ctor_body returns [ASTNode *node]
	{
	ASTNode *ci, *cs;
	node = mk_node("ctor_body");
	}
	:
	(ci = ctor_initializer {node->add_child(ci);} )?
	cs = compound_statement {node->add_child(cs);}
	;

ctor_initializer returns [ASTNode *node]
	{node = mk_node("unfinished_ctor_body");}
	:
	COLON superclass_init (COMMA superclass_init)*
	;

superclass_init
	{
	ASTNode *el;
	const char *q;
	} 
	: 
	q = qualified_id LPAREN (el = expression_list)? RPAREN
	;

dtor_head[int definition] returns [ASTNode *node]
	{
	ASTNode *dds, *dd;
	node = mk_node("dtor_head");
	}
	:
	dds = dtor_decl_spec {node->add_child(dds);}
	dd = dtor_declarator[definition] {node->add_child(dd);}
	;

dtor_decl_spec returns[ASTNode *node]
	{
	node = mk_node("dtor_decl_spec");
	}
	:
	(("inline"|"_inline"|"__inline"){node->add_child(mk_node("inline"));}
	|"virtual"{node->add_child(mk_node("virtual"));})*
	;

dtor_declarator[int definition] returns [ASTNode *node]
	{
	ASTNode *es;
	char *s;
	node = mk_node("unfinished_dtor_declaration");
	}
	:	
	s = scope_override
	TILDE ID
	{declaratorParameterList(definition);}
	LPAREN RPAREN
	{declaratorEndParameterList(definition);}
	(es = exception_specification)?
	;

dtor_body returns [ASTNode *node]
	{ASTNode *cs;
	node = mk_node("dtor_body");
	}
	:
	cs = compound_statement {node->add_child(cs);}
	{endDestructorDefinition();}
	;

parameter_list returns [ASTNode *node]
	{
	ASTNode *pdl;
	node = mk_node("parameter_list");
	}
	:	pdl = parameter_declaration_list {node->add_child(pdl);} (ELLIPSIS {node->set_leaf("...");} )?
	;

parameter_declaration_list returns [ASTNode *node]
	{
	ASTNode *p;
	}
	:	{node = mk_node("parameter_declaration_list");}
	(	p = parameter_declaration {node->add_child(p);}
		(// Have not been able to find way of stopping warning of non-determinism between alt 1 and exit branch of block
		 COMMA p = parameter_declaration {node->add_child(p);}
		)*
	)
	;

parameter_declaration returns [ASTNode *node]
	{
	ASTNode *ds, *d, *ad, *re;
	}
	:	{node = mk_node("parameter_declaration"); beginParameterDeclaration();}
		(
			{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR))&&( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
			ds = declaration_specifiers	{node->add_child(ds);}// DW 24/3/98 Mods for K & R
			(  
				(declarator)=> d = declarator {node->add_child(d);}        // if arg name given
			| 
				ad = abstract_declarator {node->add_child(ad);}    // if arg name not given  // can be empty
			)
		|
			(declarator)=> d = declarator {node->add_child(d);}			// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS {node->set_leaf("ellipsis");}
		)
		(ASSIGNEQUAL 
		 re = remainder_expression {node->add_child(re);} // DW 18/4/01 assignment_expression
		)?
	;

type_name returns [ASTNode *node]// aka type_id
	{
	ASTNode *ds, *ad;
	node = mk_node("type_name");
	}
	:
	ds = declaration_specifiers {node->add_child(ds);}
	ad = abstract_declarator {node->add_child(ad);}
	;

/* This rule looks a bit weird because (...) can happen in two
 * places within the declaration such as "void (*)()" (ptr to
 * function returning nothing).  However, the () of a function
 * can only occur after having seen either a (abstract_declarator)
 * and not after a [..] or simple '*'.  These are the only two
 * valid () func-groups:
 *    int (*)();     // ptr to func
 *    int (*[])();   // array of ptr to func
 */
abstract_declarator returns [ASTNode *node]
	{
	char *po;
	ASTNode *ad, *ad2, *ads, *cx;
	node = mk_node("abstract_declarator");
	}
	:	//{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiPtrMember) )}?
		po = ptr_operator {node->set_leaf(po);}
		ad = abstract_declarator {node->add_child(ad);}
	|	
		LPAREN ad2 = abstract_declarator RPAREN
		{node->add_child(ad2);}
		(ads = abstract_declarator_suffix {node->add_child(ads);})+
	|	
		(LSQUARE (cx = constant_expression {node->add_child(cx);})? RSQUARE {declaratorArray();}
		)+
	|	
		/* empty */
	;

abstract_declarator_suffix returns [ASTNode *node]
	{
	char *cvs;
	ASTNode *cx, *pl, *es;
	node = mk_node("abstract_declarator");
	}
	:	
		LSQUARE (cx = constant_expression {node->add_child(cx);} )? RSQUARE
		{declaratorArray();}
	|
		LPAREN
		{declaratorParameterList(0);}
		(pl = parameter_list {node->add_child(pl);} )?
		RPAREN
		cvs = cv_qualifier_seq {node->add_child(mk_node(cvs));}
		{declaratorEndParameterList(0);}
		(es = exception_specification {node->add_child(es);} )?
	;

exception_specification returns [ASTNode *node]
	{
	char *so; node = mk_node("unfinished_exception_specification");
	}
	:	"throw" 
		LPAREN 
		(	(so = scope_override ID (COMMA so = scope_override ID)? )? 
		|	ELLIPSIS
		)
		RPAREN
	;

template_head returns [ASTNode *node]
	{
	ASTNode *tpl;
	node = mk_node("template_head");
	}
	:	
		"template"
		LESSTHAN tpl = template_parameter_list {node->add_child(tpl);} GREATERTHAN
	;

template_parameter_list returns [ASTNode *node]
	{
	ASTNode *tp;
	node = mk_node("template_parameter_list");
	}
	:	
		{beginTemplateParameterList();}
		tp = template_parameter {node->add_child(tp);}
		(COMMA tp = template_parameter {node->add_child(tp);} )*
		{endTemplateParameterList();}
	;

/* Rule requires >2 lookahead tokens. The ambiguity is resolved 
 * correctly, however. According to the manual "...A template argument
 * that can be interpreted either as a parameter-declaration or a
 * type-argument (because its identifier is the name of an
 * already existing class) is taken as type-argument."
 * Therefore, any "class ID" that is seen on the input, should
 * match the first alternative here (it should be a type-argument).
 */
template_parameter returns [ASTNode *node]
	{
	ASTNode *p;
	node = mk_node("unfinished_template_parameter");
	}
	:
	(options{generateAmbigWarnings = false;}:
		("class"|"typename") 
		(id:ID  (ASSIGNEQUAL assigned_type_name)? )?
		{templateTypeParameter(id->getText().data());}
	|	
		p = parameter_declaration	// DW 30/06/03 This doesn't seem to match the current standard
	)
	;

/* This is to allow an assigned type_name in a template parameter
 *	list to be defined previously in the same parameter list,
 *	as type setting is ineffective whilst guessing
 */
assigned_type_name
	{
	char *s;
	ASTNode *ad, *ts;
	}
	:
	(options{generateAmbigWarnings = false;}:
		s = qualified_type ad = abstract_declarator	
	|
		ts = simple_type_specifier ad = abstract_declarator
	)
	;

// This rule refers to an instance of a template class or function
template_id	// aka template_class_name
	{
	ASTNode *tal;
	}
	:	ID LESSTHAN tal = template_argument_list GREATERTHAN
	;

template_argument_list returns [ASTNode *node]
	{
	ASTNode *ta;
	node = mk_node("template_argument_list");
	}
	:	ta = template_argument {node->add_child(ta);}
	(COMMA ta = template_argument {node->add_child(ta);} )*
	;

/* Here assignment_expression was changed to shift_expression to rule out
 *  x< 1<2 > which causes ambiguities. As a result, these can be used only
 *  by enclosing parentheses x<(1<2)>. This is true for x<1+2> ==> bad,
 *  x<(1+2)> ==> ok.
 */
template_argument returns [ASTNode *node]
	{
	ASTNode *tn, *sx;
	node = mk_node("template_argument");
	}
	:
		{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
		tn = type_name {node->add_child(tn);}
	|	sx = shift_expression {node->add_child(sx);}// failed in iosfwd
//	|	assignment_expression	// Inserted as per grammar summary
	;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  STATEMENTS ////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

statement_list returns [ASTNode *node]
	{
	ASTNode *s;
	node = mk_node("statement_list");
	}
	:	(s = statement {node->add_child(s);}
		)+
	;

statement returns [ASTNode *node]
	{
	ASTNode *d, *s, *ds, *e, *compstat, *sstat, *iterstat, *jumpstat, *asmnode;
	node = mk_node("statement");
	}
	:
	(	(declaration)=> d = declaration {node->add_child(d);}
	|	labeled_statement {node->add_child(mk_node("unfinished_labeled_statement"));}
	|	s = case_statement {node->add_child(s);}
	|	ds = default_statement {node->add_child(ds);}
	|	e = expression  {node->add_child(e);} SEMICOLON! {end_of_stmt();}
	|	compstat = compound_statement {node->add_child(compstat);}
	|	sstat = selection_statement {node->add_child(sstat);}
	|	iterstat = iteration_statement {node->add_child(iterstat);}
	|	jumpstat = jump_statement {node->add_child(jumpstat);}
	|	SEMICOLON! {end_of_stmt();}
	|	try_block {node->add_child(mk_node("unfinished_try_block"));}
	|	throw_statement {node->add_child(mk_node("unfinished_throw_stmt"));}
	|	asmnode = asm_block {node->add_child(asmnode);}
	)
	;

labeled_statement
	{
	ASTNode *s;
	}
	:	ID COLON s = statement
	;

case_statement returns [ASTNode *node]
	{
	ASTNode *cx, *s;
	node = mk_node("case_statement");
	}
	:	"case"
		cx = constant_expression {node->add_child(cx);}
		COLON s = statement {node->add_child(s);}
	;

default_statement returns [ASTNode *node]
	{
	ASTNode *s;
	node = mk_node("default_statement");
	}
	:	"default" COLON s = statement {node->add_child(s);}
	;

compound_statement returns [ASTNode *node]
	{ASTNode *sl;
	node = mk_node("compound_statement");
	}
	:	LCURLY 
		{ end_of_stmt(); enterNewLocalScope(); }
		(sl = statement_list {node->add_child(sl);})?
		RCURLY {exitLocalScope();}
	;

/* NOTE: cannot remove ELSE ambiguity, but it parses correctly.
 * The warning is removed with the options statement
 */
selection_statement returns [ASTNode *node]
	{
	ASTNode *x1, *s1, *s2, *x3, *s3;
	}
	:	
		"if"^ {node = mk_node("if");} LPAREN 
		x1 = expression {node->add_child(x1);} RPAREN
		s1 = statement {node->add_child(s1);}
		(options {warnWhenFollowAmbig = false;}:
		 "else"^ s2 = statement {ASTNode *elsenode = mk_node("else"); elsenode->add_child(s2); node->add_child(elsenode);})?
	|	
		"switch"^ {node = mk_node("switch");} LPAREN  x3 = expression {node->add_child(x3);} RPAREN
		s3 = statement {node->add_child(s3);}
	;

iteration_statement returns [ASTNode *node]
	{
	ASTNode *x1, *x2, *s1, *s2, *x3, *x4, *x5, *s3, *d1;
	int taken_x4 = 0, taken_x5 = 0;
	}
	:	
		"while"	 {node = mk_node("while");}
		LPAREN x1 = expression RPAREN  {node->add_child(x1);}
		s1 = statement  
		{node->add_child(s1);}
	|	
		"do" {node = mk_node("do");} s2 = statement "while" {node->add_child(s2);}
		LPAREN x2 = expression RPAREN {node->add_child(x2);}
		SEMICOLON! {end_of_stmt();} 
	|	
		"for" {node = mk_node("for");} LPAREN 
		(	(declaration)=> d1 = declaration {node->add_child(d1);}
		|	x3 = expression SEMICOLON! {end_of_stmt();} {node->add_child(x3);}
		|	SEMICOLON! {end_of_stmt(); node->add_child(mk_node("blank"));}
		)
		(x4 = expression {taken_x4 = 1; node->add_child(x4);})? SEMICOLON! {end_of_stmt();}
		{if(taken_x4 == 0) node->add_child(mk_node("blank"));}

		(x5 = expression {taken_x5 = 1; node->add_child(x5);})?
		{if(taken_x5 == 0) node->add_child(mk_node("blank"));}
		RPAREN s3 = statement	  {node->add_child(s3);}
	;

jump_statement returns [ASTNode *node]
	{
	ASTNode *x;
	}
	:	
	(	"goto" gotoid:ID SEMICOLON! {end_of_stmt();}
		{node = mk_node("jump_goto"); node->set_leaf(gotoid->getText().data());}
	|	"continue" SEMICOLON! {end_of_stmt();}
		{node = mk_node("jump_statement"); node->set_leaf("continue");}
	|	"break" SEMICOLON! {end_of_stmt();}
		{node = mk_node("jump_statement"); node->set_leaf("break");}
		// DW 16/05/03 May be problem here if return is followed by a cast expression 
	|	"return" {in_return = true;}
//		(	options{warnWhenFollowAmbig = false;}:
//			(LPAREN {(qualifiedItemIsOneOf(qiType) )}? ID RPAREN)=> 
//			LPAREN ID RPAREN (expression)?	// This is an unsatisfactory fix for problem in xstring re "return (allocator);"
//											//  and in xlocale re return (_E)(_Tolower((unsigned char)_C, &_Ctype));
//			//{printf("%d CPP_parser.g jump_statement Return fix used\n",LT(1).getLine());}
//		|	(expression  
//		/* nfd: fixme: I commented out the above weirdo thing */
//		)?	SEMICOLON!
            {node = mk_node("jump_statement"); node->set_leaf("return");}
	   (x = expression {node->add_child(x);} )? SEMICOLON!
		{ in_return = false; end_of_stmt(); }
	)
	;

try_block
	{
	ASTNode *compstat;
	}
	:	"try" compstat = compound_statement (handler)*
	;


handler
	{
	ASTNode *compstat;
	}
	:	"catch"
		{exceptionBeginHandler();}
		{declaratorParameterList(1);}
		LPAREN exception_declaration RPAREN
		{declaratorEndParameterList(1);}
		compstat = compound_statement
		{exceptionEndHandler();}
	;

exception_declaration
	{
	ASTNode *pdl;
	}
	:	pdl = parameter_declaration_list
	;

/* This is an expression of type void according to the ARM, which
 * to me means "statement"; it removes some ambiguity to put it in
 * as a statement also.
 */
throw_statement
	{
	ASTNode *ax;
	}
	:	"throw" (ax = assignment_expression) ? SEMICOLON! { end_of_stmt();}
	;

using_declaration returns [ASTNode *node]
	{
	const char *qid;
	node = mk_node("unfinished_using_declaration");
	}
	:	"using"
		("namespace" qid = qualified_id	// Using-directive
		|qid = qualified_id				// Using-declaration
		)
		SEMICOLON! {end_of_stmt();}
	;

asm_block returns [ASTNode *node]
	{node = mk_node("asm_block");}
	:   std_asm_block | gcc_asm_block
	;

std_asm_block
	:	("_asm"|"__asm") LCURLY (~RCURLY)* RCURLY 
	;

gcc_asm_block
	:   ("__asm__" | "asm") ("volatile" | "__volatile__" | "__volatile")?
            LPAREN asm_code
            ((COLON | SCOPE) (asm_reg_spec)?)*
            RPAREN
	;

asm_code
	: (StringLiteral)+
	;

asm_reg_spec
	{
	ASTNode *ex1, *ex2;
	}
	:
        (LSQUARE ID RSQUARE)?
        StringLiteral
        (LPAREN ex1 = expression RPAREN)?
        (COMMA (LSQUARE ID RSQUARE)? StringLiteral
        (LPAREN ex2 = expression RPAREN)? )*
	;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  EXPRESSIONS ///////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

expression returns [ASTNode *node]
	{ASTNode *x;}
	:	x = assignment_expression {node = x;}
		(COMMA x = assignment_expression {node = exprnode_acc(node, x, "comma");})*
	;

/* right-to-left for assignment op */
assignment_expression returns [ASTNode *node]
	{
	ASTNode *cx, *rx;
	char *leaf;
	}
	:	cx = conditional_expression {node = cx;}
		(	(ASSIGNEQUAL {leaf="assignequals";} |TIMESEQUAL {leaf="timesequals";}|DIVIDEEQUAL {leaf="dividesequals";}
			|MINUSEQUAL{leaf="minusequals";}|PLUSEQUAL {leaf="plusequals";}
			|MODEQUAL{leaf="modequals";}
			|SHIFTLEFTEQUAL{leaf="shiftleftequals";}
			|SHIFTRIGHTEQUAL{leaf="shiftrightequals";}
			|BITWISEANDEQUAL{leaf="bitwiseandequals";}
			|BITWISEXOREQUAL{leaf="bitwisexorequals";}
			|BITWISEOREQUAL{leaf="bitwiseorequals";}
			)
			rx = remainder_expression {node = exprnode_acc(node, rx, leaf);}
		)?
	;

remainder_expression returns [ASTNode *node]
	{
	ASTNode *x;
	}
	:
		(	(conditional_expression (COMMA|SEMICOLON|RPAREN)
			)=>
			{assign_stmt_RHS_found += 1;}
			x = assignment_expression {node = x;}
			{if (assign_stmt_RHS_found > 0) assign_stmt_RHS_found -= 1;}
			{if (assign_stmt_RHS_found <= 0) assert("Error in remainder expr");}
		|	
			x = assignment_expression {node = x;}
		)
	;

conditional_expression returns [ASTNode *node]
	{
	ASTNode *lx, *e, *cx;
	}
	:	
		lx = logical_or_expression {node = lx;}
		(QUESTIONMARK e = expression COLON cx = conditional_expression
		{node = mk_node("expression"); node->add_child(lx);}
		{node->add_child(e); node->add_child(cx);}
		{node->set_leaf("c_ternary");}
		)?
	;

constant_expression returns [ASTNode *node]
	{
	ASTNode *cs;
	}
	:	
		cs = conditional_expression {node = cs;}
	;

logical_or_expression returns [ASTNode *node]
	{
	ASTNode *x;
	}
	:	
		x = logical_and_expression {node = x;}
		(OR x = logical_and_expression {node = exprnode_acc(node, x, "logicalor");})* 
	;

logical_and_expression returns [ASTNode *node]
	{
	ASTNode *x;
	}
	:	
		x = inclusive_or_expression {node = x;}
		(AND x = inclusive_or_expression {node = exprnode_acc(node, x, "logicaland");})* 
	;

inclusive_or_expression returns [ASTNode *node]
	{
	ASTNode *x;
	}
	:	
		x = exclusive_or_expression {node = x;}
		(BITWISEOR x = exclusive_or_expression {node = exprnode_acc(node, x, "bitwiseor");})*
	;

exclusive_or_expression returns [ASTNode *node]
	{
	ASTNode *x;
	}
	:	
		x = and_expression {node = x;}
		(BITWISEXOR x = and_expression {node = exprnode_acc(node, x, "bitwisexor");})*
	;

and_expression returns [ASTNode *node]
	{
	ASTNode *x;
	}
	:	
	x = equality_expression {node = x;}
	(AMPERSAND x = equality_expression {node = exprnode_acc(node, x, "bitwiseand");})*
	;

equality_expression returns [ASTNode *node]
	{
	ASTNode *x;
	char *leaf;
	}
	:	
		x = relational_expression {node = x;}
		((NOTEQUAL {leaf = "notequals";}| EQUAL {leaf = "equals";})
		x = relational_expression {node = exprnode_acc(node, x, leaf);})*
	;

relational_expression returns [ASTNode *node]
	{
	ASTNode *x;
	char *leaf;
	}
	:	x = shift_expression {node = x;}
		(options {warnWhenFollowAmbig = false;}:
			(	LESSTHAN {leaf = "lessthan";}
			|	GREATERTHAN {leaf = "greaterthan";}
			|	LESSTHANOREQUALTO {leaf = "lessthanorequals";}
			|	GREATERTHANOREQUALTO {leaf = "greaterthanorequals";}
			)
		 x = shift_expression {node = exprnode_acc(node, x, leaf);}
		)*
	;

shift_expression returns [ASTNode *node]
	{
	ASTNode *x;
	char *leaf;
	}
	:	x = additive_expression {node = x;}
	((SHIFTLEFT {leaf = "shiftleft";}| SHIFTRIGHT {leaf = "shiftright";})
	x = additive_expression {node = exprnode_acc(node, x, leaf);})*
	;

/* See comment for multiplicative_expression regarding #pragma */
additive_expression returns [ASTNode *node]
	{
	ASTNode *x;
	char *leaf;
	}
	:	x = multiplicative_expression {node = x;}
		(options{warnWhenFollowAmbig = false;}:
			(PLUS {leaf = "add";}| MINUS {leaf = "subtract";})
			x = multiplicative_expression
			{node = exprnode_acc(node, x, leaf);}
		)*
	;

/* ANTLR has trouble dealing with the analysis of the confusing unary/binary
 * operators such as STAR, AMPERSAND, PLUS, etc...  With the #pragma (now "(options{warnWhenFollowAmbig = false;}:" etc.)
 * we simply tell ANTLR to use the "quick-to-analyze" approximate lookahead
 * as full LL(k) lookahead will not resolve the ambiguity anyway.  Might
 * as well not bother.  This has the side-benefit that ANTLR doesn't go
 * off to lunch here (take infinite time to read grammar).
 */
multiplicative_expression returns [ASTNode *node]
	{
	ASTNode *x;
	char *leaf;
	}
	:	x = pm_expression {node = x;}
		(options{warnWhenFollowAmbig = false;}:
			(STAR {leaf = "multiply";}| DIVIDE {leaf = "divide";}| MOD {leaf = "modulus";})
			x = pm_expression {node = exprnode_acc(node, x, leaf);}
		)*
	;

/* Pointer to member operators*/
pm_expression returns [ASTNode *node]
	{
	ASTNode *x;
	char *leaf;
	}
	:	x = cast_expression {node = x;}
	((DOTMBR {leaf = ".*";}| POINTERTOMBR {leaf = "->*";})
	x = cast_expression {node = exprnode_acc(node, x, leaf);})*
	;

/* The string "( ID" can be either the start of a cast or
 * the start of a unary_expression.  However, the ID must
 * be a type name for it to be a cast.  Since ANTLR can only hoist
 * semantic predicates that are visible without consuming a token,
 * the semantic predicate in rule type_name is not hoisted--hence, the
 * rule is reported to be ambiguous.  I am manually putting in the
 * correctly hoisted predicate.
 *
 * Ack! Actually "( ID" might be the start of "(T(expr))" which makes
 * the first parens just an ordinary expression grouping.  The solution
 * is to look at what follows the type, T.  Note, this could be a
 * qualified type.  Yucko.  I believe that "(T(" can only imply
 * function-style type cast in an expression (...) grouping.
 *
 * We DO NOT handle the following situation correctly at the moment:
 * Suppose you have
 *    struct rusage rusage;
 *    return (rusage.fp);
 *    return (rusage*)p;
 * Now essentially there is an ambiguity here. If rusage is followed by any
 * postix operators then it is an identifier else it is a type name. This
 * problem does not occur in C because, unless the tag struct is attached,
 * rusage is not a type name. However in C++ that restriction is removed.
 * No *real* programmer would do this, but it's in the C++ standard just for
 * fun..
 *
 * Another fun one (from an LL standpoint):
 *
 *   (A::B::T *)v;      // that's a cast of v to type A::B::T
 *   (A::B::foo);    // that's a simple member access
 *
 * The qualifiedItemIs(1) function scans ahead to what follows the
 * final "::" and returns qiType if the item is a type.  The offset of
 * '1' makes it ignore the initial LPAREN; normally, the offset is 0.
 */

cast_expression returns [ASTNode *node]
	{
	char *tq, *po;
	ASTNode *ts, *indirection, *cx, *x;
	}
	:
	(compound_literal) => x = compound_literal {node = x;} /* nfd */
	|
		{node = mk_node("expression");}
		// DW 23/06/03
		(LPAREN (type_qualifier)? type_specifier[dsInvalid] (ptr_operator)* RPAREN)=>
		 {node->set_leaf("cast");}
		 LPAREN (tq = type_qualifier {node->add_child(mk_node(tq));})?
		 ts = type_specifier[dsInvalid] {node->add_child(ts);}
		 {indirection = mk_node("indirection"); node->add_child(indirection);}
		 (po = ptr_operator {indirection->extend_leaf(po);})*
		 RPAREN cx = cast_expression {node->add_child(cx);}
	|  
		x = unary_expression {node = x;}	// handles outer (...) of "(T(expr))"
	;

unary_expression returns [ASTNode *node]
	{
	char *op;
	ASTNode *x;
	}
	:
		(	//{!(LA(1)==TILDE && LA(2)==ID)||qualifiedItemIsOneOf(qiVar|qiFun|qiDtor|qiCtor)}?
			(postfix_expression)=> x = postfix_expression {node = x;}
		|	PLUSPLUS x = unary_expression
				{node = mk_node("expression"); node->set_leaf("++."); node->add_child(x);}
		|	MINUSMINUS x= unary_expression
				{node = mk_node("expression"); node->set_leaf("--."); node->add_child(x);}
		|	op = unary_operator x = cast_expression
				{node = mk_node("expression"); node->set_leaf(op); node->add_child(x);}
		|	"sizeof" {node = mk_node("expression"); node->set_leaf("sizeof");}
			(// see comment for rule cast_expression for info on predicate
			 // JEL NOTE 3/31/96 -- This won't work -- you really need to
			 // call qualifiedItemIsOneOf(qiType|qiCtor,1)
			 // The context should also be ( LPAREN (SCOPE|ID) )
			 //	( LPAREN ID ) => {isTypeName((LT(2)->getText()).data())}?
			 {(!(((LA(1)==LPAREN&&(LA(2)==ID))))||(isTypeName((LT(2)->getText()).data())))}?
				LPAREN x = type_name RPAREN {node->add_child(x);}
			|	x = unary_expression {node->add_child(x);}
			)
		|   {node = mk_node("expression");}
			(s:SCOPE {node->set_leaf(s->getText().data());})?
			(x = new_expression {node->add_child(x);}
			|x = delete_expression {node->add_child(x);}
			)
		)
	;

postfix_expression returns [ASTNode *node]
	{
	char *po;
	ASTNode *ts, *el, *x, *x2, *idxpr, *idxpr2, *prevnode, *px;
	// Purpose?
	DeclSpecifier ds = dsInvalid;
	}
	:
	(	
		options {warnWhenFollowAmbig = false;}:
		// Function-style cast must have a leading type
		{!(LA(1)==LPAREN)}?
		(ts = simple_type_specifier LPAREN RPAREN LPAREN)=>	// DW 01/08/03 To cope with problem in xtree (see test10.i)
		 ts = simple_type_specifier LPAREN RPAREN LPAREN (el = expression_list)? RPAREN
		{node = mk_node("unfinished_postfix-expr");}
	|
		{(LA(1) != LPAREN)}?
		(ts = simple_type_specifier LPAREN)=>
		 ts = simple_type_specifier LPAREN (el = expression_list)? RPAREN
		{node = mk_node("unfinished_postfix-expr-2");}
	|  
		px = primary_expression {node = px;}
		{prevnode = node;}
		(options {warnWhenFollowAmbig = false;}:
        	LSQUARE x = expression RSQUARE
			{node = mk_node("expression"); node->set_leaf("arrayindex"); node->add_child(prevnode); node->add_child(x); prevnode = node;}
		|	LPAREN
			{node = mk_node("expression"); node->set_leaf("call"); node->add_child(prevnode);}
			(x2 = expression_list {node->add_child(x2);} )?
			{prevnode = node;}
			RPAREN
		|	DOT idxpr = id_expression
			{node = mk_node("expression"); node->set_leaf("postfixdot"); node->add_child(prevnode); node->add_child(idxpr);}
			{prevnode = node;}
		|	POINTERTO idxpr2 = id_expression
			{node = mk_node("expression"); node->set_leaf("postfixptr");}
			{node->add_child(prevnode); node->add_child(idxpr2); prevnode = node;}
		|	PLUSPLUS 
			{node = mk_node("expression"); node->set_leaf("plusplus"); node->add_child(prevnode);}
			{prevnode = node;}
		|	MINUSMINUS 
			{node = mk_node("expression"); node->set_leaf("minusminus"); node->add_child(prevnode);}
			{prevnode = node;}
		)*
	|
		("dynamic_cast"|"static_cast"|"reinterpret_cast"|"const_cast")	// Note const_cast in elsewhere
		LESSTHAN ts = type_specifier[ds] (po = ptr_operator)? GREATERTHAN
		LPAREN x = expression RPAREN
		{node = mk_node("unfinished_postfix-expr-3");}
	)
	;

primary_expression returns [ASTNode *node]
	{
	ASTNode *x;
	}
	:	x = id_expression {node = x;}
	|	x = constant {node = x;}
	|	"this" {node = mk_node("expression"), node->set_leaf("this");}
	|	LPAREN x = expression RPAREN {node = x;}
	;

compound_literal returns [ASTNode *node]
	{
	ASTNode *tn, *i;
	node = mk_node("compound_literal");
	}
	/* nfd: ISO C99 "compound literals" feature (extension) */
	: LPAREN tn = type_name {node->add_child(tn);} RPAREN
	LCURLY i = initializer {node->add_child(i);} RCURLY
	;

id_expression returns [ASTNode *node]
	{
	const char *s, *o;
	node = mk_node("expression");
	node->set_leaf("id_expression");
	}
	:
		s = scope_override {node->set_value(s);}
		(	id1:ID {node->extend_value(id1->getText().data());}
		|	OPERATOR o = optor {node->extend_value("operator"); node->extend_value(o);}
		/* nfd: commented this out 2007-07-06 -- it seems like we can just use unary_operator in the normal way?! */
		/*|	TILDE {node->extend_value("~");}
			(STAR {node->extend_value("*");})?
			id2:ID {node->extend_value(id2->getText().data());}	// DW 29/07/03 STAR included to allow for *_S = ~*_S; seen in vector */
		)
	;

unary_operator returns[char *op]
	:	AMPERSAND {op = "unary_ampersand";}
	|	STAR {op = "unary_pointsto";}
	|	PLUS {op = "unary_plus";}
	|	MINUS {op = "unary_minus";}
	|	TILDE {op = "unary_tilde";}
	|	NOT {op = "unary_not";}
	;

/* JEL The first ()? is used to resolve "new (expr) (type)" because both
 * (expr) and (type) look identical until you've seen the whole thing.
 *
 * new_initializer appears to be conflicting with function arguments as
 * function arguments can follow a primary_expression.  [This is a full
 * LL(k) versus LALL(k) problem.  Enhancing context by duplication of
 * some rules might handle this.]
 */
new_expression returns [ASTNode *node]
	{
	ASTNode *el, *tn;
	}
	:
	(  
		"new"
		((LPAREN expression_list RPAREN)=> 
			LPAREN el = expression_list RPAREN)?
		(new_type_id | LPAREN tn = type_name RPAREN)
		(options{warnWhenFollowAmbig = false;}:	
		(new_initializer)=> new_initializer)?
	)
	{node = mk_node("unfinished_new-expr");}
	;

new_initializer
	{
	ASTNode *el;
	}
	:	LPAREN (el = expression_list)? RPAREN
	;

new_type_id
	{
	ASTNode *ds;
	}
	:	ds = declaration_specifiers 
		(options {warnWhenFollowAmbig = false;}:
		 //{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiPtrMember) )}?
			new_declarator 
		)?
	;

new_declarator
	{
	char *po;
	}
	:	//{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiPtrMember) )}?  
		//ptr_to_member cv_qualifier_seq 
		po = ptr_operator
		(options {warnWhenFollowAmbig = false;}:
		new_declarator ) ?
	|	direct_new_declarator
	;

ptr_operator returns[char *oper]
	{
	char *ptm;
	oper = "UNKNOWN";
	}
	:	(	AMPERSAND {oper = "&";}	{is_address = true;}
		|	("_cdecl"|"__cdecl") {oper = "_cdecl";}
		|	("_near"|"__near") {oper = "_near";}
		|	("_far"|"__far") {oper = "_far";}
		|	"__interrupt" {oper = "__interrupt";}
		|	("pascal"|"_pascal"|"__pascal") {oper = "pascal";}
		|	("_stdcall"|"__stdcall") {oper = "_stdcall";}
		|	ptm = ptr_to_member	{oper = ptm;}// e.g. STAR 
		)	
   ;

// Match A::B::*
ptr_to_member returns[char *ptm]
	{
	char *so, *cvs;
	static char s[CPPParser_MaxQualifiedItemSize+1];
	s[0] = '\0';
	}
	:
	so = scope_override {strcat(s, so);} STAR {strcat(s, "*");} {is_pointer = true;}
	cvs = cv_qualifier_seq {strcat(s, cvs);}
	{ptm = s;}
	;

// Match the A::B::C:: or nothing
scope_override returns [char *s]
	{
	ASTNode *tal;
	static char sitem[CPPParser_MaxQualifiedItemSize+1];
	sitem[0]='\0';
	}
	:
		//{!(qualifiedItemIsOneOf(qiType))}?
		(SCOPE {strcat(sitem,"::");} )?
		(	options {warnWhenFollowAmbig = false;}:
			{scopedItem()}?
			id:ID (LESSTHAN tal=template_argument_list GREATERTHAN)? SCOPE
			{
			//printf("scope_override entered\n");
			strcat(sitem,(id->getText()).data());
			strcat(sitem,"::");
			}
		)*
	{s = sitem;}
	;

/* The "[expression]" construct conflicts with the "new []" construct
 * (and possibly others).  We used approximate lookahead for the "new []"
 * construct so that it would not try to compute full LL(2) lookahead.
 * Here, we use #pragma approx again because anytime we see a [ followed
 * by token that can begin an expression, we always want to loop.
 * Approximate lookahead handles this correctly.  In fact, approximate
 * lookahead is the same as full lookahead when all but the last lookahead
 * depth are singleton sets; e.g., {"["} followed by FIRST(expression).
 */
direct_new_declarator
	{
	ASTNode *x;
	}
	:
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE x = expression RSQUARE
		)+
	;

delete_expression returns [ASTNode *node]
	{
	ASTNode *cx;
	node = mk_node("delete");
	}
	:	"delete" (LSQUARE RSQUARE {node->set_leaf("arrayindex");} )?
		cx = cast_expression {node->add_child(cx);}
	;

expression_list returns [ASTNode *node]
	{
	ASTNode *x;
	node = mk_node("expression");
	}
	:	x = assignment_expression
		{node->add_child(x);}
		(COMMA x = assignment_expression {node = exprnode_acc(node, x, "comma");})*
	;

constant returns [ASTNode *node]
	{
	ASTNode *litnode;
	node = mk_node("expression"); node->set_leaf("literal");
	litnode = mk_node("literal"); node->add_child(litnode);
	}
	:
	(	oi:OCTALINT {litnode->set_leaf(oi->getText().data()); litnode->set_name("int");}
	|	di:DECIMALINT {litnode->set_leaf(di->getText().data()); litnode->set_name("int");}
	|	hi:HEXADECIMALINT {litnode->set_leaf(hi->getText().data()); litnode->set_name("int");}
	|	cl:CharLiteral {litnode->set_leaf(cl->getText().data()); litnode->set_name("char");}
	|	(sl:StringLiteral {litnode->extend_leaf(sl->getText().data());})+ {litnode->set_name("string");}
	|	f1:FLOATONE {litnode->set_leaf(f1->getText().data()); litnode->set_name("float");}
	|	f2:FLOATTWO {litnode->set_leaf(f2->getText().data()); litnode->set_name("float");}
	|	"true" {litnode->set_leaf("true"); litnode->set_name("bool");}
	|	"false" {litnode->set_leaf("false"); litnode->set_name("bool");}
	) 
	;

optor  returns[const char *out]
	{
	const char *x;
	}
	:
		"new" {out = "new";}
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE RSQUARE | )		// check syntax
	|   
		"delete" {out = "delete";}
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE RSQUARE | )		// check syntax
	|	LPAREN RPAREN {out = "()";}
	|	LSQUARE RSQUARE {out = "arrayindex";}
	|	x = optor_simple_tokclass {out = x;}	//OPTOR_SIMPLE_TOKCLASS
	;

//Zuo 5/11/2001
// This is the equivalent to "#tokclass OPTOR_SIMPLE_TOKCLASS" in cplusplus.g

optor_simple_tokclass returns[const char *out]
	:
    (PLUS|MINUS|STAR|DIVIDE|MOD|BITWISEXOR|AMPERSAND|BITWISEOR|TILDE|NOT|
	 SHIFTLEFT|SHIFTRIGHT|
	 ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MODEQUAL|PLUSEQUAL|MINUSEQUAL|
	 SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL|BITWISEXOREQUAL|BITWISEOREQUAL|
	 EQUAL|NOTEQUAL|LESSTHAN|GREATERTHAN|LESSTHANOREQUALTO|GREATERTHANOREQUALTO|OR|AND|
	 PLUSPLUS|MINUSMINUS|COMMA|POINTERTO|POINTERTOMBR
	)
	{out = LT(1)->getText().data();}
	;

// Zuo 19/11/01 from next line, the Lexer is derived from stdCParser.g

class CPPLexer extends Lexer;

options
	{
	k = 3;
	exportVocab = STDC;
	testLiterals = true;
	}

// DW 4/11/02 put in to support manual hoisting
tokens
	{
	OPERATOR = "operator";
	}

{
ANTLR_USE_NAMESPACE(antlr)LineObject lineObject;
ANTLR_USE_NAMESPACE(std)string originalSource;
int deferredLineCount;

int	_line;

void setOriginalSource(ANTLR_USE_NAMESPACE(std)string src) 
	{
	originalSource = src;
	lineObject.setSource(src);
	}

void setSource(ANTLR_USE_NAMESPACE(std)string src)
	{
	lineObject.setSource(src);
	}
  

void newline() 
	{ 
    CharScanner::newline();
    }
}

/* Operators: */

ASSIGNEQUAL     : '=' ;
COLON           : ':' ;
COMMA           : ',' ;
QUESTIONMARK    : '?' ;
SEMICOLON       : ';' ;
POINTERTO       : "->" ;

/*
// DOT & ELLIPSIS are commented out since they are generated as part of
// the Number rule below due to some bizarre lexical ambiguity shme.
// DOT  :       '.' ;
// ELLIPSIS      : "..." ;
*/

LPAREN          : '(' ;
RPAREN          : ')' ;
LSQUARE         : '[' ;
RSQUARE         : ']' ;
LCURLY          : '{' ;
RCURLY          : '}' ;

EQUAL           : "==" ;
NOTEQUAL        : "!=" ;
LESSTHANOREQUALTO     : "<=" ;
LESSTHAN              : "<" ;
GREATERTHANOREQUALTO  : ">=" ;
GREATERTHAN           : ">" ;

DIVIDE          : '/' ;
DIVIDEEQUAL     : "/=" ;
PLUS            : '+' ;
PLUSEQUAL       : "+=" ;
PLUSPLUS        : "++" ;
MINUS           : '-' ;
MINUSEQUAL      : "-=" ;
MINUSMINUS      : "--" ;
STAR            : '*' ;
TIMESEQUAL      : "*=" ;
MOD             : '%' ;
MODEQUAL        : "%=" ;
SHIFTRIGHT      : ">>" ;
SHIFTRIGHTEQUAL : ">>=" ;
SHIFTLEFT       : "<<" ;
SHIFTLEFTEQUAL  : "<<=" ;

AND            : "&&" ;
NOT            : '!' ;
OR             : "||" ;

AMPERSAND       : '&' ;
BITWISEANDEQUAL : "&=" ;
TILDE           : '~' ;
BITWISEOR       : '|' ;
BITWISEOREQUAL  : "|=" ;
BITWISEXOR      : '^' ;
BITWISEXOREQUAL : "^=" ;

//Zuo: the following tokens are come from cplusplus.g

POINTERTOMBR    : "->*" ;
DOTMBR          : ".*"  ;

SCOPE           : "::"  ;

// DW 10/10/02
// Whitespace -- ignored
Whitespace	
	:	(	(' ' |'\t' | '\f')
			// handle newlines
		|	(	"\r\n"  // MS
			|	'\r'    // Mac
			|	'\n'    // Unix 
			)	{newline();}
			// handle continuation lines
		|	(	"\\\r\n"  // MS
			|	"\\\r"    // Mac
			|	"\\\n"    // Unix 
			)	{newline();}
		)	
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
	;

Comment  
	:	"/*"   
		(	{LA(2) != '/'}? '*'
		|	EndOfLine {newline();}
		|	~('*'| '\r' | '\n')
		)*
		"*/" {_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
	;

CPPComment
	:	"//" (~('\n' | '\r'))* EndOfLine
 		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}                     
	;

PREPROC_DIRECTIVE
	options{paraphrase = "a line directive";}
	:	'#' LineDirective
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();} 
	;

protected
ALL_TO_NL
	: (~(' ' | '\t' | '\f')) (~('\n' | '\r'))*
	;

protected 
LineDirective
	:
		("line")?  // this would be for if the directive started "#line"
		(Space)+
		n:Decimal
		(Space)+
		(sl:ALL_TO_NL)
		{
		process_line_directive((sl->getText()).data(), (n->getText()).data());  // see main()
		}
		EndOfLine
	;

protected  
Space
	:	(' ' | '\t' | '\f')
	;


Pragma
	:	('#' "pragma" (~('\r' | '\n'))* EndOfLine)
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}
	;

Error
	:	('#' "error" (~('\r' | '\n'))* EndOfLine)
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}
	;

/* Literals: */

/*
 * Note that we do NOT handle tri-graphs nor multi-byte sequences.
 */

/*
 * Note that we can't have empty character constants (even though we
 * can have empty strings :-).
 */
CharLiteral
	:	'\'' (Escape | ~( '\'' )) '\''
	;

/*
 * Can't have raw imbedded newlines in string constants.  Strict reading of
 * the standard gives odd dichotomy between newlines & carriage returns.
 * Go figure.
 */
StringLiteral
	:	'"'
		( Escape
		|	(	"\\\r\n"   // MS 
			|	"\\\r"     // MAC
			|	"\\\n"     // Unix
			)	{newline();}
		|	~('"' | '\r' | '\n' | '\\')
		)*
		'"'
	;

protected
EndOfLine
	:	(	options{generateAmbigWarnings = false;}:
			"\r\n"  // MS
		|	'\r'    // Mac
		|	'\n'    // Unix
		)
	;

/*
 * Handle the various escape sequences.
 *
 * Note carefully that these numeric escape *sequences* are *not* of the
 * same form as the C language numeric *constants*.
 *
 * There is no such thing as a binary numeric escape sequence.
 *
 * Octal escape sequences are either 1, 2, or 3 octal digits exactly.
 *
 * There is no such thing as a decimal escape sequence.
 *
 * Hexadecimal escape sequences are begun with a leading \x and continue
 * until a non-hexadecimal character is found.
 *
 * No real handling of tri-graph sequences, yet.
 */

protected
Escape  
	:	'\\'
		( options{warnWhenFollowAmbig=false;}:
		  'a'
		| 'b'
		| 'f'
		| 'n'
		| 'r'
		| 't'
		| 'v'
		| '"'
		| '\''
		| '\\'
		| '?'
		| ('0'..'3') (options{warnWhenFollowAmbig=false;}: Digit (options{warnWhenFollowAmbig=false;}: Digit)? )?
		| ('4'..'7') (options{warnWhenFollowAmbig=false;}: Digit)?
		| 'x' (options{warnWhenFollowAmbig=false;}: Digit | 'a'..'f' | 'A'..'F')+
		)
	;

/* Numeric Constants: */

protected
Digit
	:	'0'..'9'
	;

protected
Decimal
	:	('0'..'9')+
	;

protected
LongSuffix
	:	'l'
	|	'L'
	;

protected
UnsignedSuffix
	:	'u'
	|	'U'
	;

protected
FloatSuffix
	:	'f'
	|	'F'
	;

protected
Exponent
	:	('e' | 'E') ('+' | '-')? (Digit)+
	;

protected
Vocabulary
	:	'\3'..'\377'
	;

Number
	:	( (Digit)+ ('.' | 'e' | 'E') )=> (Digit)+
		( '.' (Digit)* (Exponent)? {_ttype = FLOATONE;} //Zuo 3/12/01
		| Exponent                 {_ttype = FLOATTWO;} //Zuo 3/12/01
		)                          //{_ttype = DoubleDoubleConst;}
		(FloatSuffix               //{_ttype = FloatDoubleConst;}
		|LongSuffix                //{_ttype = LongDoubleConst;}
		)?

	|	("...")=> "..."            {_ttype = ELLIPSIS;}

	|	'.'                        {_ttype = DOT;}
		(	(Digit)+ (Exponent)?   {_ttype = FLOATONE;} //Zuo 3/12/01
                                   //{_ttype = DoubleDoubleConst;}
			(FloatSuffix           //{_ttype = FloatDoubleConst;}
			|LongSuffix            //{_ttype = LongDoubleConst;}
			)?
		)?

	|	'0' ('0'..'7')*            //{_ttype = IntOctalConst;}
		(LongSuffix                //{_ttype = LongOctalConst;}
		|UnsignedSuffix            //{_ttype = UnsignedOctalConst;}
		)*                         {_ttype = OCTALINT;}

	|	'1'..'9' (Digit)*          //{_ttype = IntIntConst;}
		(LongSuffix                //{_ttype = LongIntConst;}
		|UnsignedSuffix            //{_ttype = UnsignedIntConst;}
		)*                         {_ttype = DECIMALINT;}  

	|	'0' ('x' | 'X') ('a'..'f' | 'A'..'F' | Digit)+
                                   //{_ttype = IntHexConst;}
		(LongSuffix                //{_ttype = LongHexConst;}
		|UnsignedSuffix            //{_ttype = UnsignedHexConst;}
		)*                         {_ttype = HEXADECIMALINT;}   
	;

ID
	options {testLiterals = true;}
	:	( 'a'..'z' | 'A'..'Z' | '_' )
		( 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' )*
	;
